﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Jemgine.Data
{
    public class Anchor : Terminal, Translatable
    {
        [Microsoft.Xna.Framework.Content.ContentSerializerIgnore]
        public ReferenceTarget Target = null;

        public int TargetID = -1;
        public Vector2 Position;

        public Anchor Clone()
        {
            Anchor NewAnchor = new Anchor();
            NewAnchor.Position = Position;
            NewAnchor.Target = Target;
            NewAnchor.TargetID = TargetID;
            return NewAnchor;
        }

        #region Terminal Members

        public void SetTarget(object obj)
        {
            Target = obj as ReferenceTarget;
        }

        public object GetTarget()
        {
            return Target;
        }

        #endregion

        #region Translatable Members

        object Translatable.PrepareToTranslate()
        {
            return Position;
        }

        void Translatable.ApplyTranslation(object Tag, Vector2 MouseDelta)
        {
            Vector2 OriginalPosition = (Vector2)Tag;
            Position = OriginalPosition + MouseDelta;
        }

        void Translatable.Snap(Snapper Snapper)
        {
            Position = Snapper.SnapPosition(Position);
        }

        #endregion
    }

	public class Dynamic : MapElement, EditorDrawable, Translatable, ReferenceTarget
	{
        static public Box2D.XNA.Body GetEntityBody(ReferenceTarget Element)
        {
            Data.EntityRecord E = Element as Data.EntityRecord;
            if (E == null) return null;
            Engine.Physics EntityPhysics = E.GetComponent<Engine.Physics>();
            if (EntityPhysics == null) return null;
            return EntityPhysics.PhysicsBody;
        }

        static public Box2D.XNA.Joint GetJoint(ReferenceTarget Element)
        {
            Data.Dynamic E = Element as Data.Dynamic;
            if (E == null) return null;
            return E.Joint;
        }

        public Vector2 GetDimensions()
        {
            return new Vector2(2, 2);
        }        

        public Vector2 Position { get; set; }

		public virtual Box2D.XNA.JointDef GetJointDef() 
		{ 
			throw new NotImplementedException(); 
		}

        [Microsoft.Xna.Framework.Content.ContentSerializerIgnore]
        public int ReferenceID { get; set; }

        
        [Microsoft.Xna.Framework.Content.ContentSerializerIgnore]
        internal Box2D.XNA.Joint Joint = null;

		public bool ConnectedCollide { get; set; }

        public List<Anchor> Anchors = new List<Anchor>();

        protected void AddAnchor() { Anchors.Add(new Anchor()); }

		public Dynamic()
		{
            ReferenceID = -1;
			ConnectedCollide = false;
		}



        #region EditorDrawable Members

        public void DrawSelectedAnchor(EditorDrawData Context, int Anchor, SelectionType Type)
        {
            Context.Renderer.Color = EditorDrawData.DrawColor(Type);
            Context.Renderer.DrawPoint(Anchors[Anchor].Position);
        }

        public void Draw(int ID, EditorDrawData Context, SelectionType Selected)
        {

            Context.Renderer.Color = EditorDrawData.DrawColor(Selected);

            if (Selected == Data.SelectionType.NotSelected) 
                Context.AddLabel(ID.ToString() + " " + this.GetType().Name, Position, LabelType.Name);

            Context.Renderer.DrawBox(Position - new Vector2(1, 1), Position + new Vector2(1, 1), 0.1f);

            for (int A = 0; A < Anchors.Count; ++A)
            {
                Anchor anchor = Anchors[A];
                Context.Renderer.DrawPoint(anchor.Position);
                Context.Renderer.DrawLine(anchor.Position, this.Position, 0.2f);
                if (anchor.Target != null)
                    Context.Renderer.DrawLine(anchor.Position, anchor.Target.GetWorldPosition(), 0.2f);

                if (Selected != Data.SelectionType.NotSelected)
                    Context.AddLabel(A.ToString(), anchor.Position, LabelType.Output);
            }

        }

        #endregion



        #region MapElement Members

        public void GatherDependencies(Action<String, String, String> Callback) { }

        public Vector2 GetPosition()
        {
            return Position;
        }

        public void SetPosition(Vector2 Pos) { Position = Pos; }

        public Jemgine.Engine.Selection.Types SelectionType()
        {
            return Jemgine.Engine.Selection.Types.MapElement;
            //return Jemgine.Engine.Selection.Types.Dynamic;
        }


        public Vector2 GetWorldPosition()
        {
            return Position;
        }

        public MapElement Clone()
        {
            Dynamic NewDynamic = (Dynamic)(Activator.CreateInstance(this.GetType()));

            foreach (System.Reflection.PropertyInfo Property in this.GetType().GetProperties())
                if (Property.CanRead && Property.CanWrite)
                    Property.SetValue(NewDynamic, Property.GetValue(this, null), null);

            NewDynamic.Anchors.Clear();
            foreach (Anchor anchor in Anchors)
                NewDynamic.Anchors.Add(anchor.Clone());

            return NewDynamic;
        }

        public void PostProcess(Vector2 Offset, MapData Data, Jemgine.Engine.Simulation Sim)
        {
            this.Position += Offset;
            foreach (var Anchor in Anchors)
            {
                Anchor.Position += Offset;
                Anchor.Target = Data.GetAnchorTarget(Anchor);
            }
        }

        public int AssignInputIDs(int NextID)
        {
            return NextID;
        }

        public int AssignTargetIDs(int NextID)
        {
            ReferenceID = NextID;
            return NextID + 1;
        }

         public void ClearAllIDs() { ReferenceID = -1; }

        public void EnumerateTargets(List<InputTerminal> Inputs, List<ReferenceTarget> Targets)
        {
            Targets.Add(this);
        }

        public void PreProcess()
        {
            foreach (Anchor Anchor in Anchors)
            {
                if (Anchor.Target == null) Anchor.TargetID = -1;
                else Anchor.TargetID = Anchor.Target.ReferenceID;
            }            
        }

        #endregion

        #region Translatable Members

        object Translatable.PrepareToTranslate()
        {
            return Position;
        }

        void Translatable.ApplyTranslation(object Tag, Vector2 MouseDelta)
        {
            Vector2 OriginalPosition = (Vector2)Tag;
            Position = OriginalPosition + MouseDelta;
        }

        void Translatable.Snap(Snapper Snapper)
        {
            Position = Snapper.SnapPosition(Position);
        }

        #endregion
    }

}
